package utility;
import java.io.File;
import java.io.IOException;
import java.util.GregorianCalendar;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * @author sebastian
 *
 */
public final class XmlHelper {
	/**
	 * 
	 */
	private XmlHelper() {
	}
	
	/**
	 * 
	 */
	private static Document xmlDoc;
	
	/**
	 * @param xmlDoc the xmlDoc to set
	 */
	public static void setXmlDoc(final Document xmlDoc) {
		XmlHelper.xmlDoc = xmlDoc;
	}

	/**
	 * @return getter for xmlDoc
	 */
	public static Document getXmlDoc() {
		return xmlDoc;
	}
	
	/**
	 * @throws ParserConfigurationException 
	 * 
	 */
	public static void init() throws ParserConfigurationException {
		DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
		docFactory.setNamespaceAware(true);
		docFactory.setValidating(true);
		docFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
				"http://www.w3.org/2001/XMLSchema");
        docFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", "file:./test1.xsd");

		DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
		xmlDoc = docBuilder.newDocument();
	}
	
	/**
	 * @param tagName name of the tag
	 * @param value value of the element (string)
	 * @return the created element
	 */
	public static Element createTextElement(final String tagName, final String value) {
		Element e  = xmlDoc.createElement(tagName);
		e.appendChild(xmlDoc.createTextNode(value));
		return e;
	}
	
	/**
	 * @param tagName name of the tag
	 * @param date value of the element (date)
	 * @return the created element
	 */
	public static Element createDateElement(final String tagName, final GregorianCalendar date) {
		Element result  = xmlDoc.createElement(tagName);
		result.appendChild(createTextElement("year", String.valueOf(date.get(GregorianCalendar.YEAR))));
		result.appendChild(createTextElement("month", String.valueOf(date.get(GregorianCalendar.MONTH))));
		result.appendChild(createTextElement("day", String.valueOf(date.get(GregorianCalendar.DAY_OF_MONTH))));
		result.appendChild(createTextElement("hour", String.valueOf(date.get(GregorianCalendar.HOUR_OF_DAY))));
		result.appendChild(createTextElement("minute", String.valueOf(date.get(GregorianCalendar.MINUTE))));
		return result;
	}
	
	/**
	 * @param xmlFile xml-file-path
	 * @param schemaFile xsd-file-path
	 * @param nameSpaceAware use namespaces?
	 * @param errHandler error handler (anonymous possible)
	 * @throws Exception lots
	 */
	public static void validateXML(final File xmlFile, final File schemaFile, final boolean nameSpaceAware,
			final ErrorHandler errHandler) throws Exception {
		try {
			SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
			Source schemaSource = new StreamSource(schemaFile);
			Schema schema = schemaFactory.newSchema(schemaSource);
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setNamespaceAware(true);
			dbf.setSchema(schema);
			DocumentBuilder db = dbf.newDocumentBuilder();
			db.setErrorHandler(errHandler);
			db.parse(xmlFile); 
			} catch (SAXParseException spe) {
			String message = "Parser error!\n  URI: " + spe.getSystemId() + "\n  Line: " 
			+ spe.getLineNumber() + "\n  Message: " + spe.getMessage();
			Exception e = spe;
			if (spe.getException() != null) {
				e = spe.getException();
			} 
			throw new Exception(message, e);
			} catch (SAXException sxe) {
			Exception e = sxe;
			if (sxe.getException() != null) {
				e = sxe.getException();
			} 
			throw new Exception("Error during parsing.", e);
		} catch (ParserConfigurationException pce) {
			throw new Exception("Parser configuration is invalid.", pce);
		} catch (IOException ioe) {
			throw new Exception("Error reading file.", ioe);
		}
	}
	
	/**
	 * @param xmlElement input element
	 * @param tagName name of the child element to search
	 * @return the first childelement with a matching tag name
	 */
	public static Element getFirstChildWithTagName(final Element xmlElement, final String tagName) {
		NodeList nl = xmlElement.getChildNodes();
		for (int i = 0; i < nl.getLength(); ++i) {
			if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
				Element e = (Element) nl.item(i);
				if (e.getTagName().equalsIgnoreCase(tagName)) {
					return e;
				}
			}
		}
		return null;
	}
	
	/**
	 * @param xmlElement Element which converts to GregorianCalendar
	 * @return GregorianCalender
	 */
	public static GregorianCalendar elementToDate(final Element xmlElement) {
		
		GregorianCalendar newDate = new GregorianCalendar(
				Integer.parseInt(xmlElement.getElementsByTagName("year").item(0).getTextContent()), 
				Integer.parseInt(xmlElement.getElementsByTagName("month").item(0).getTextContent()), 
				Integer.parseInt(xmlElement.getElementsByTagName("day").item(0).getTextContent()), 
				Integer.parseInt(xmlElement.getElementsByTagName("hour").item(0).getTextContent()), 
				Integer.parseInt(xmlElement.getElementsByTagName("minute").item(0).getTextContent()));
		
		return newDate;
	}
}
